/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package za.co.pas.business.abstracts;

import za.co.pas.business.message.MessageObj;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.ListIterator;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TransactionRequiredException;
import org.apache.log4j.Logger;
import za.co.pas.business.data.Company;
import za.co.pas.business.factory.EMFFactory;
import za.co.pas.business.message.StatusMessage;
import za.co.pas.business.message.StatusMessageObject;

/**
 *
 * @author alabuschagne
 */
public abstract class AbstractDataModel
{

    protected PropertyChangeSupport propertyChangeSupport;
    private static Logger logger = Logger.getLogger(AbstractDataModel.class);
    @PersistenceContext
    protected static EntityManager em = EMFFactory.getInstance().getEntityManagerFactory().createEntityManager();
    protected boolean connectionOk = false;

    public AbstractDataModel()
    {
        propertyChangeSupport = new PropertyChangeSupport(this);
    }

    public void shutDown()
    {
        EMFFactory.getInstance().closeEmf();
    }

    public static String doMD5(String strIn)
    {
        try
        {
            MessageDigest m = MessageDigest.getInstance("MD5");
            m.update(strIn.getBytes(), 0, strIn.length());
            BigInteger i = new BigInteger(1, m.digest());
            return String.format("%1$032X", i).toUpperCase();
        }
        catch (NoSuchAlgorithmException nsae)
        {
            logger.error(nsae.getMessage(), nsae);
            return null;
        }
    }

    public void persistGenericList(List theList) throws EntityExistsException
    {
        try
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting list to database", StatusMessageObject.SMO_TYPE_BUSY_START));
            em.getTransaction().begin();
            ListIterator it = theList.listIterator();
            while (it.hasNext())
            {
                em.persist(it.next());
                em.flush();
                firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting list item to database", StatusMessageObject.SMO_TYPE_WRITE));
            }
            em.getTransaction().commit();
        }
        catch (IllegalStateException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (IllegalArgumentException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (TransactionRequiredException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting list to database - done", StatusMessageObject.SMO_TYPE_BUSY_END));
    }

    public void persistGenericObject(Object theObject) throws EntityExistsException
    {
        try
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting object to database", StatusMessageObject.SMO_TYPE_BUSY_START));
            em.getTransaction().begin();
            em.persist(theObject);
            em.flush();
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting object to database", StatusMessageObject.SMO_TYPE_WRITE));
            em.getTransaction().commit();
        }
        catch (IllegalStateException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (IllegalArgumentException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (TransactionRequiredException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (Exception ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
            ex.printStackTrace();
        }
        firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting object to database - done", StatusMessageObject.SMO_TYPE_BUSY_END));
    }

    public void mergseGenericObject(Object theObject) throws EntityExistsException
    {
        try
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting object to database", StatusMessageObject.SMO_TYPE_BUSY_START));
            em.getTransaction().begin();
            em.persist(theObject);
            em.flush();
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting object to database", StatusMessageObject.SMO_TYPE_WRITE));
            em.getTransaction().commit();
        }
        catch (IllegalStateException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (IllegalArgumentException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (TransactionRequiredException ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
        }
        catch (Exception ex)
        {
            firePropertyChange(new StatusMessage(StatusMessageObject.SMO_ERROR, "Writing error: " + ex.getMessage(), StatusMessageObject.SMO_TYPE_WRITE));
            logger.error(ex.getMessage(), ex);
            ex.printStackTrace();
        }
        firePropertyChange(new StatusMessage(StatusMessageObject.SMO_INFO, "Persisting object to database - done", StatusMessageObject.SMO_TYPE_BUSY_END));
    }

    public boolean isConnectionOk()
    {
        logger.debug("Connection is open: " + em.isOpen());
        return em.isOpen();
    }

    protected void setConnectionOk(boolean b)
    {
        connectionOk = b;
    }

    public void addPropertyChangeListener(PropertyChangeListener listener)
    {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener)
    {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    protected void firePropertyChange(MessageObj msgObj)
    {
        propertyChangeSupport.firePropertyChange(msgObj.getPropertyName(), msgObj.getOldValue(), msgObj.getNewValue());
    }
}
